#ifndef _XLCD_SCREEN
#define _XLCD_SCREEN

#include <TFT_eSPI.h>
#include <lvgl.h>
#include "SPIFFS.h"

#define XPT2046_IRQ 36
#define XPT2046_MOSI 32
#define XPT2046_MISO 39
#define XPT2046_CLK 25
#define XPT2046_CS 33
#define LCD_BACK_LIGHT_PIN 21
#define ConsoleInfo Serial
// use first channel of 16 channels (started from zero)
#define LEDC_CHANNEL_0 0

// use 12 bit precission for LEDC timer
#define LEDC_TIMER_12_BIT 12

// use 5000 Hz as a LEDC base frequency
#define LEDC_BASE_FREQ 5000

static const uint16_t screenWidth  = 240;
static const uint16_t screenHeight = 320;

static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[4096];

TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); /* TFT instance */

void xtouch_screen_setBackLedOn()
{
    pinMode(4, OUTPUT);
    pinMode(16, OUTPUT);
    pinMode(17, OUTPUT);
    digitalWrite(4, LOW);
    digitalWrite(16, LOW);
    digitalWrite(17, LOW); // The LEDs are "active low", meaning HIGH == off, LOW == on
}

void xtouch_screen_dispFlush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
    uint32_t w = (area->x2 - area->x1 + 1);
    uint32_t h = (area->y2 - area->y1 + 1);

    tft.startWrite();
    tft.setAddrWindow(area->x1, area->y1, w, h);
    tft.pushColors((uint16_t *)&color_p->full, w * h, true);
    tft.endWrite();

    lv_disp_flush_ready(disp);
}

void xtouch_screen_ledcAnalogWrite(uint8_t channel, uint32_t value, uint32_t valueMax = 255)
{
    // calculate duty, 4095 from 2 ^ 12 - 1
    uint32_t duty = (4095 / valueMax) * min(value, valueMax);

    // write duty to LEDC
    ledcWrite(channel, duty);
}

void screen_setBrightness(byte brightness)
{
    xtouch_screen_ledcAnalogWrite(LEDC_CHANNEL_0, brightness);
}

void xtouch_screen_setBackLedOff()
{
    pinMode(4, OUTPUT);
    pinMode(16, OUTPUT);
    pinMode(17, OUTPUT);
    digitalWrite(4, HIGH);
    digitalWrite(16, HIGH);
    digitalWrite(17, HIGH); // The LEDs are "active low", meaning HIGH == off, LOW == on
}


void screen_setup()
{
    Serial.begin(115200);
    Serial.setTimeout(0);
    if (!SPIFFS.begin(true)) {
        ConsoleInfo.println("[XTouch][SCREEN] SPIFFS Mount Failed");
        return;
    } else {
        ConsoleInfo.println("[XTouch][SCREEN] SPIFFS Mount Successful");
    }
    delay(200);
    ConsoleInfo.println("[XTouch][SCREEN] Setup");
    pinMode(XPT2046_CS, OUTPUT);
    pinMode(TFT_CS, OUTPUT);

    digitalWrite(XPT2046_CS, HIGH); // Touch controller chip select (if used)
    digitalWrite(TFT_CS, HIGH);     // TFT screen chip select
    xtouch_screen_setBackLedOff();

    lv_init();
    tft.init();

    ledcSetup(LEDC_CHANNEL_0, LEDC_BASE_FREQ, LEDC_TIMER_12_BIT);
    ledcAttachPin(LCD_BACK_LIGHT_PIN, LEDC_CHANNEL_0);

    tft.setRotation( 3 ); /* Landscape orientation, flipped */

    lv_disp_draw_buf_init(&draw_buf, buf, NULL, 4096);
    /*Initialize the display*/
    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = screenHeight;
    disp_drv.ver_res = screenWidth;
    disp_drv.flush_cb = xtouch_screen_dispFlush;
    disp_drv.draw_buf = &draw_buf;
    lv_disp_drv_register(&disp_drv);
}

#endif